package com.hk.commons.util;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

/**
 * 集合工具类
 *
 * @author kevin
 * @date 2017年9月1日下午1:31:18
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public abstract class CollectionUtils {

    /**
     * 是否为一个空集合
     *
     * @param coll coll
     * @return boolean
     */
    public static boolean isNotEmpty(Collection<?> coll) {
        return !isEmpty(coll);
    }

    /**
     * 长度是否不为0
     *
     * @param iterable iterable
     * @return true or false
     */
    public static boolean isNotEmpty(Iterable<?> iterable) {
        return !isEmpty(iterable);
    }

    /**
     * 长度是否为0
     *
     * @param iterable iterable
     * @return true or false
     */
    public static boolean isEmpty(Iterable<?> iterable) {
        return size(iterable) == 0;
    }

    /**
     * 转换为 String 数组
     *
     * @param it it
     * @return String[]
     */
    public static String[] toArray(Iterable<String> it) {
        return Objects.isNull(it) ? new String[0] :
                StreamSupport.stream(it.spliterator(), false).toArray(String[]::new);
    }

    public static Object[] toObjectArray(Iterable<?> it) {
        return Objects.isNull(it) ? new Object[0] :
                StreamSupport.stream(it.spliterator(), false).toArray(Object[]::new);
    }

    /**
     * 判断iterable元素长度
     *
     * @param iterable iterable
     * @return size
     */
    public static int size(Iterable<?> iterable) {
        if (Objects.isNull(iterable)) {
            return 0;
        }
        if (iterable instanceof Collection<?> coll) {
            return coll.size();
        }
        return StreamSupport.stream(iterable.spliterator(), false).toArray().length;
    }

    /**
     * iterable 转换为集合
     *
     * @param iterable iterable
     * @return {@link ArrayList}
     */
    public static <T> Collection<T> toCollection(Iterable<T> iterable) {
        return toCollection(iterable, 10);
    }


    /**
     * 将map的 key,value转换为 string
     *
     * @return 假设separator为&,keyValueSeparator为=,则转换的结果为 key1=xxx&key2=xxx
     */
    public static String joinIgnoreNull(Map<String, ?> map, String separator, String keyValueSeparator) {
        StringBuilder sb = new StringBuilder();
        if (isNotEmpty(map)) {
            int size = map.size();
            int index = 0;
            for (Map.Entry<String, ?> entry : map.entrySet()) {
                Object value = entry.getValue();
                if (Objects.nonNull(value)) {
                    sb.append(entry.getKey()).append(keyValueSeparator).append(ConverterUtils.defaultConvert(value, String.class));
                    if (index < size) {
                        sb.append(separator);
                    }
                }
                index++;
            }
        }
        return sb.toString();
    }

    /**
     * iterable 转换为集合
     *
     * @param iterable      iterable
     * @param estimatedSize estimatedSize
     * @return {@link ArrayList}
     */
    public static <T> Collection<T> toCollection(Iterable<T> iterable, int estimatedSize) {
        return toList(iterable, estimatedSize);
    }

    public static <T> List<T> toList(Iterable<T> iterable) {
        return toList(iterable, 10);
    }

    public static <T> List<T> toList(Iterable<T> iterable, int estimatedSize) {
        if (Objects.isNull(iterable)) {
            return new ArrayList<>(estimatedSize);
        }
        if (iterable instanceof List<T> list) {
            return list;
        }
        if (iterable instanceof Collection<T> coll) {
            return new ArrayList<>(coll);
        }
        List<T> list = new ArrayList<>(estimatedSize);
        iterable.forEach(list::add);
        return list;
    }


    public static boolean isEmpty(Map<?, ?> map) {
        return Objects.isNull(map) || map.isEmpty();
    }

    /**
     * 是否为一个空Map
     *
     * @param map map
     * @return boolean
     */
    public static boolean isNotEmpty(Map<?, ?> map) {
        return Objects.nonNull(map) && !map.isEmpty();
    }

    /**
     * 如果 list2中的元素不能空，添加list2的元素添加到 list1中
     *
     * @param list1 list1
     * @param list2 list2
     * @return boolean
     */
    public static <T> boolean addAll(Collection<T> list1, Collection<T> list2) {
        return isNotEmpty(list2) && list1.addAll(list2);
    }

    /**
     * 是否包含指定元素
     *
     * @param it      it
     * @param element element
     * @return boolean
     */
    public static boolean contains(Iterable<?> it, Object element) {
        if (Objects.isNull(it)) {
            return false;
        }
        if (it instanceof Collection<?> coll) {
            return coll.contains(element);
        }
        return StreamSupport.stream(it.spliterator(), false)
                .anyMatch(item -> ObjectUtils.nullSafeEquals(item, element));
    }

    /**
     * 集合中是否包含任意的元素
     *
     * @param coll     集合
     * @param elements 元素
     */
    @SafeVarargs
    public static <T> boolean containsAny(Collection<T> coll, T... elements) {
        return isNotEmpty(coll)
                && ArrayUtils.isNotEmpty(elements)
                && org.springframework.util.CollectionUtils.containsAny(coll, Arrays.asList(elements));
    }

    /**
     * Map根据Value 从小到大排序
     *
     * @param result result
     * @return Map
     */
    public static <V extends Comparable<? super V>> Map<String, V> sortMapByValue(Map<String, V> result) {
        return sortMapByValue(result, false);
    }

    /**
     * <pre>
     * Map根据Value 排序
     * </pre>
     *
     * @param result   result
     * @param reversed 是否反转
     * @return Map
     */
    public static <V extends Comparable<? super V>> Map<String, V> sortMapByValue(Map<String, V> result,
                                                                                  boolean reversed) {
        if (org.springframework.util.CollectionUtils.isEmpty(result)) {
            return Collections.emptyMap();
        }
        var finalMap = new LinkedHashMap<String, V>();
        result.entrySet().stream()
                .sorted(reversed ? Map.Entry.<String, V>comparingByValue().reversed()
                        : Map.Entry.comparingByValue())
                .forEachOrdered(e -> finalMap.put(e.getKey(), e.getValue()));
        return finalMap;
    }

    /**
     * 获取 Map key 的值，转换为 String 类型
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static String getStringValue(Map<?, ?> map, Object key) {
        return getValue(map, key, String.class);
    }

    /**
     * 获取 Map key 的值，转换为 String 类型，如果 值为 Null， 返回默认值
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static String getStringValue(Map<?, ?> map, Object key, String defaultValue) {
        return getValueOrDefault(map, key, defaultValue, String.class);
    }

    /**
     * 获取 Map key 的值，转换为 Boolean 类型
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static Boolean getBooleanValue(Map<?, ?> map, Object key) {
        return getValue(map, key, Boolean.class);
    }

    /**
     * 获取 Map key 的值，转换为 Boolean 类型，如果 值为 Null， 返回默认值
     *
     * @param map          map
     * @param key          key
     * @param defaultValue defaultValue
     * @return defaultValue
     */
    public static Boolean getBooleanValue(Map<?, ?> map, Object key, Boolean defaultValue) {
        return getValueOrDefault(map, key, defaultValue, Boolean.class);
    }

    /**
     * 获取 Map key 的值，转换为 Long 类型
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static Long getLongValue(Map<?, ?> map, Object key) {
        return getValue(map, key, Long.class);
    }

    /**
     * 获取 Map key 的值，转换为 Long 类型，如果 值为 Null， 返回默认值
     *
     * @param map map
     * @param key key
     * @return defaultValue defaultValue
     */
    public static Long getLongValue(Map<?, ?> map, Object key, Long defaultValue) {
        return getValueOrDefault(map, key, defaultValue, Long.class);
    }

    /**
     * 获取 Map key 的值，转换为 Integer 类型
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static Integer getIntegerValue(Map<?, ?> map, Object key) {
        return getValue(map, key, Integer.class);
    }

    /**
     * 获取 Map key 的值，转换为 Integer 类型，如果 值为 Null， 返回默认值
     *
     * @param map          map
     * @param key          key
     * @param defaultValue defaultValue
     * @return value
     */
    public static Integer getIntegerValue(Map<?, ?> map, Object key, Integer defaultValue) {
        return getValueOrDefault(map, key, defaultValue, Integer.class);
    }

    /**
     * 获取 Map key 的值，转换为 Byte 类型
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static Byte getByteValue(Map<?, ?> map, Object key) {
        return getValue(map, key, Byte.class);
    }

    /**
     * 获取 Map key 的值，转换为 Byte 类型，如果 值为 Null， 返回默认值
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static Byte getByteValue(Map<?, ?> map, Object key, Byte defaultValue) {
        return getValueOrDefault(map, key, defaultValue, Byte.class);
    }

    /**
     * 获取 Map key 的值，转换为 Short 类型
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static Short getShortValue(Map<?, ?> map, Object key) {
        return getValue(map, key, Short.class);
    }

    /**
     * 获取 Map key 的值，转换为 Short 类型，如果 值为 Null， 返回默认值
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static Short getByteValue(Map<?, ?> map, Object key, Short defaultValue) {
        return getValueOrDefault(map, key, defaultValue, Short.class);
    }

    /**
     * 获取Map key 的 value值,如果不存在，返回 null
     *
     * @param map map
     * @param key key
     * @return Map
     */
    public static Map<?, ?> getMapValue(Map<?, ?> map, Object key) {
        return getValue(map, key, Map.class);
    }

    /**
     * 获取Map key 的 value值,如果不存在，返回 null
     *
     * @param map map
     * @param key key
     * @return T
     */
    public static <T> T getValue(Map<?, ?> map, Object key, Class<T> clazz) {
        return getValueOrDefault(map, key, null, clazz);
    }

    /**
     * 获取Map key 的 value值，如果不存在，返回 defaultValue
     *
     * @param map map
     * @param key key
     * @return value
     */
    public static <T> T getValueOrDefault(Map<?, ?> map, Object key, T defaultValue, Class<T> clazz) {
        if (isEmpty(map)) {
            return defaultValue;
        }
        var value = map.get(key);
        return Objects.isNull(value) ? defaultValue : ConverterUtils.defaultConvert(value, clazz);
    }

    /**
     * Map根据Key 排序
     *
     * @param result result
     * @return Map
     */
    public static <K extends Comparable<? super K>> Map<K, Object> sortMapByKey(Map<K, Object> result) {
        return sortMapByKey(result, false);
    }

    /**
     * <pre>
     * Map根据Key 排序
     * </pre>
     *
     * @param result   result
     * @param reversed 是否反转
     * @return Map
     */
    public static <K extends Comparable<? super K>> Map<K, Object> sortMapByKey(Map<K, Object> result,
                                                                                boolean reversed) {
        if (isEmpty(result)) {
            return LinkedHashMap.newLinkedHashMap(0);
        }
        return result.entrySet().stream()
                .sorted(reversed ? Map.Entry.<K, Object>comparingByKey().reversed()
                        : Map.Entry.comparingByKey())
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                        (oldValue, newValue) -> oldValue, LinkedHashMap::new));
    }

    /**
     * 过滤为空的可变数组元素，添加到指定集合
     *
     * @param coll coll
     * @param args args
     */
    @SafeVarargs
    public static <T> void addAllNotNull(Collection<T> coll, final T... args) {
        addAllNull(coll, false, args);
    }

    /**
     * 添加元素到集合
     *
     * @param coll             指定集合
     * @param containNullValue 是否将空值元素也添加到集合中
     * @param args             是添加到集合中的元素
     */
    @SafeVarargs
    public static <T> void addAllNull(Collection<T> coll, boolean containNullValue, final T... args) {
        if (ArrayUtils.isNotEmpty(args)) {
            for (var t : args) {
                if (containNullValue || Objects.nonNull(t)) {
                    coll.add(t);
                }
            }
        }
    }

    /**
     * 获取集合第一个元素
     *
     * @param coll coll
     * @return Map
     */
    public static <T> Optional<T> getFirstOrDefault(Collection<T> coll) {
        return isEmpty(coll) ? Optional.empty() : Optional.ofNullable(coll.iterator().next());
    }

    /**
     * 多个Map的值合并成一个map
     *
     * @param values values
     * @return Map
     */
    @SafeVarargs
    public static Map<String, Integer> addOrMergeIntegerValues(Map<String, Integer>... values) {
        return addOrMergeMapValues(Integer::sum, values);
    }

    /**
     * 多个Map的值合并成一个map
     *
     * @param values values
     * @return Map
     */
    @SafeVarargs
    public static Map<String, Double> addOrMergeDoubleValues(Map<String, Double>... values) {
        return addOrMergeMapValues(Double::sum, values);
    }

    /**
     * 多个Map的值合并成一个map
     *
     * @param values values
     * @return Map
     */
    @SafeVarargs
    public static Map<String, Long> addOrMergeLongValues(Map<String, Long>... values) {
        return addOrMergeMapValues(Long::sum, values);
    }

    /**
     * 多个Map的值合并成一个map
     *
     * @param values values
     * @return Map
     */
    @SafeVarargs
    public static Map<String, BigDecimal> addOrMergeBigDecimalValues(Map<String, BigDecimal>... values) {
        return addOrMergeMapValues(BigDecimal::add, values);
    }

    /**
     * 多个Map的值合并成一个map
     *
     * @param values values
     * @return Map
     */
    @SafeVarargs
    public static Map<String, BigInteger> addOrMergeBigIntegerValues(Map<String, BigInteger>... values) {
        return addOrMergeMapValues(BigInteger::add, values);
    }

    @SafeVarargs
    public static <T extends Number> Map<String, T> addOrMergeMapValues(final BiFunction<T, T, T> biFunction,
                                                                        Map<String, T>... map) {
        var result = new HashMap<String, T>();
        if (ArrayUtils.isEmpty(map)) {
            return result;
        }
        for (var mapItem : map) {
            for (var entry : mapItem.entrySet()) {
                result.compute(entry.getKey(),
                        (key, val) -> Objects.isNull(val) ? entry.getValue() : biFunction.apply(val, entry.getValue()));
            }
        }
        return result;
    }
}
